using System;
using System.Globalization;
using System.Windows.Forms;
using System.Security.Principal;

using SBPweb.Localization;

using SBPweb.Contracts;
using SBPweb.Modules.Communication;
using SBPweb.Modules.Modularity;
using SBPweb.Modules.Smartparts;
using SBPweb.Modules.Logging;

using SBPweb.Controls.Windows.Docking;

using SBPweb.Presentation.Windows.Forms.Controls;
using SBPweb.Presentation.Windows.Forms.Host.Controls;
using SBPweb.Contracts.Implementation;

namespace SBPweb.Presentation.Windows.Forms.Host
{
	public partial class MainForm : Form, IModuleHost
	{
        private int mMemoryRefreshIntervall = 60;

		public event EventHandler OnApplicationClosing;

		#region Private fields

		private IMessageQueue pMessageQueue = null;
		private DockManagerControl pSmartpartList;
		private IPrincipal pPrincipal;
		private SplashForm pSplashForm;
		private bool pIsTransparent;
		private static ErrorForm mErrorForm = new ErrorForm();

		private const string persistenceKey = "SBPweb.Presentation.Windows.Forms.Host";

		private delegate DialogResult ShowErrorFormDelegate(Exception ex);

		#endregion

		#region Constructor logic

        public MainForm()
        {
            int.TryParse(Properties.Settings.Default.MemoryRefreshIntervall, out mMemoryRefreshIntervall);

            if (mMemoryRefreshIntervall < 60 && mMemoryRefreshIntervall >= 0)
            {
                mMemoryRefreshIntervall = 60;
            }

            DockingUserControl.EnableTooltips = Properties.Settings.Default.EnableTooltips;

            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor, true);

			LayoutService ls = new LayoutService(this);
			this.ModuleLoader.Services.Add(typeof(ILayoutService), ls);

            InitializeComponent();
            InitializeModules();
            InitiliazeMessageBoxes();

            LoadPersistency();
        }

		#endregion

		#region Property accessors

        public NotifyIcon NotifyIcon
        {
            get
            {
                return niNotify;
            }
        }

		public new IMenuList Menu
		{
			get
			{
				return pMenu;
			}
		}

		public IMenuList StatusBar
		{
			get
			{
				return pStatusBar;
			}
		}

		public IMessageQueue Messages
		{
			get
			{
				return pMessageQueue;
			}
		}

		public ISmartpartList Smartparts
		{
			get
			{
				return pSmartpartList;
			}
		}

		public ILayoutProvider LayoutProvider
		{
			get
			{
				return (ILayoutProvider)pSmartpartList.DockingManager;
			}
		}

		public ILogManager LogManager
		{
			get
			{
				return Program.LogManager;
			}
		}

		public ModuleLoader ModuleLoader
		{
			get
			{
				return Program.Loader;
			}
		}

		public IPrincipal SecurityPrincipal
		{
			get
			{
				return pPrincipal;
			}
			set
			{
				pPrincipal = value;
			}
		}

		public bool IsTransparentBackgroundUsed
		{
			get
			{
				return pIsTransparent;
			}
			set
			{
				if (pIsTransparent = value)
				{
					this.TransparencyKey = this.BackColor = System.Drawing.Color.Magenta;
				}
				else
				{
					this.TransparencyKey = System.Drawing.Color.Transparent;
				}
			}
		}

		public IStatePersistenceService PersistenceService
		{
			get
			{
				try
				{
					return Program.Loader.Services[typeof(IStatePersistenceService)] as IStatePersistenceService;
				}
				catch 
				{
					return null; 
				}
			}
		}

		public string PersistencyKey
		{
			get 
			{
				return persistenceKey; 
			}
		}

		public CultureInfo[] SupportedCultures
		{
			get
			{
				return Program.SupportedCultures;
			}
		}

		public ModuleHostType HostType
		{
			get
			{
				return ModuleHostType.WindowsForms;
			}
		}

		#endregion

		#region Methods

		public void InitializeModules()
		{
			this.Visible = false;

			pSplashForm = new SplashForm();
			pSplashForm.Show(this);

			//pMessageQueue = new MessageQueueControl(this);
			pSmartpartList = new DockManagerControl(pToolStripContainer.ContentPanel, Program.Loader, null, this);

			Menu.Insert(1, (pSmartpartList as DockManagerControl).WindowMenu as MenuItemControl);

			//Menu.ItemAdded += new EventHandler<MenuEventArgs>(Menu_ItemAdded);
			//Menu.ItemRemoved += new EventHandler<MenuEventArgs>(Menu_ItemRemoved);

			//Messages.Peeked += new EventHandler<MessageEventArgs>(Messages_Peeked);
			//Messages.Enqueued += new EventHandler<MessageEventArgs>(Messages_Enqueued);
			//Messages.Dequeued += new EventHandler<MessageEventArgs>(Messages_Dequeued);

			//Smartparts.ItemAdded += new EventHandler<SmartpartEventArgs>(Smartparts_ItemAdded);
			//Smartparts.ItemRemoved += new EventHandler<SmartpartEventArgs>(Smartparts_ItemRemoved);

			Program.Loader.ModuleGroupLoaded += new EventHandler(Loader_ModuleGroupLoaded);

			Application.DoEvents();
		}

		private void InitiliazeMessageBoxes()
		{
			System.Collections.Generic.Dictionary<SBPweb.Controls.Windows.Common.MsgBoxButtons, string> msgBoxTexts = new System.Collections.Generic.Dictionary<SBPweb.Controls.Windows.Common.MsgBoxButtons, string>();
			msgBoxTexts.Add(SBPweb.Controls.Windows.Common.MsgBoxButtons.OK, "OK");
			msgBoxTexts.Add(SBPweb.Controls.Windows.Common.MsgBoxButtons.Yes, "Yes");
			msgBoxTexts.Add(SBPweb.Controls.Windows.Common.MsgBoxButtons.Retry, "Retry");
			msgBoxTexts.Add(SBPweb.Controls.Windows.Common.MsgBoxButtons.Ignore, "Ignore");
			msgBoxTexts.Add(SBPweb.Controls.Windows.Common.MsgBoxButtons.Abort, "Abort");
			msgBoxTexts.Add(SBPweb.Controls.Windows.Common.MsgBoxButtons.No, "No");
			msgBoxTexts.Add(SBPweb.Controls.Windows.Common.MsgBoxButtons.Cancel, "Cancel");
			SBPweb.Controls.Windows.Common.MessageBox.ButtonTexts = msgBoxTexts;
		}

		public void ShowAboutBox()
		{
			pSplashForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
			if (!pSplashForm.Visible)
			{
				pSplashForm.ShowDialog(this);
			}
			pSplashForm.FormBorderStyle = FormBorderStyle.None;
		}

		public static DialogResult ShowErrorForm(Exception ex)
		{
			if (mErrorForm.InvokeRequired)
			{
				return (DialogResult)Enum.Parse(typeof(DialogResult), mErrorForm.Invoke(new ShowErrorFormDelegate(ShowErrorForm), new object[] { ex }).ToString());
			}
			mErrorForm.Exception = ex;
			return mErrorForm.ShowDialog();
		}

		public void Terminate()
		{
			if (OnApplicationClosing != null)
			{
				OnApplicationClosing(null, null);
			}

			SavePersistency();

			(pSmartpartList as DockManagerControl).Finalize();

			Application.ExitThread();
		}

		public void SetCulture(CultureInfo ci)
		{
			if (ci != null)
			{
				ResourceHandler.SetCurrentCulture(ci);
				LocalizationExtender.Culture = ci;
			}
		}

		#endregion

		#region Event handlers

        #region unused event handlers
        /*
		protected void Menu_ItemAdded(object sender, MenuEventArgs e)
		{
		}

		protected void Menu_ItemRemoved(object sender, MenuEventArgs e)
		{
		}

		protected void Messages_Peeked(object sender, MessageEventArgs e)
		{
		}

		protected void Messages_Enqueued(object sender, MessageEventArgs e)
		{
		}

		protected void Messages_Dequeued(object sender, MessageEventArgs e)
		{
		}

		protected void Smartparts_ItemAdded(object sender, SmartpartEventArgs e)
		{
		}

		protected void Smartparts_ItemRemoved(object sender, SmartpartEventArgs e)
		{
		}
        */
        #endregion

        protected delegate void Loader_ModuleGroupLoadedHandler(object sender, EventArgs e);

		protected void Loader_ModuleGroupLoaded(object sender, EventArgs e)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new Loader_ModuleGroupLoadedHandler(Loader_ModuleGroupLoaded), sender, e);
				return;
			}

			pSplashForm.Hide();

            if (mMemoryRefreshIntervall >= 0)
            {
                MemoryManagement.MinimizeWorkingSets();
                MemoryManagement.IntervalInSeconds = mMemoryRefreshIntervall;
                MemoryManagement.Enabled = true;
                //MemoryManagement.Enabled = false;
                this.Activated += new EventHandler(MainForm_Activated);
            }
		}

        void MainForm_Activated(object sender, EventArgs e)
        {
            if (mMemoryRefreshIntervall >= 0 ) //disabled if -1
                MemoryManagement.MinimizeWorkingSets();
        }

		#endregion

		#region NotifyIcon events

		private void niNotify_DoubleClick(object sender, EventArgs e)
		{
			this.Show();
			if (this.WindowState == FormWindowState.Minimized)
			{
				this.WindowState = FormWindowState.Normal;
			}
			this.BringToFront();
		}

		private void niNotify_BalloonTipClicked(object sender, EventArgs e)
		{
			this.Show();
			if (this.WindowState == FormWindowState.Minimized)
			{
				this.WindowState = FormWindowState.Normal;
			}
			this.BringToFront();
		}

		#region NotifyIcon - ContexMenuStip events

		private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
		{
			ShowAboutBox();
		}

		private void showToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.Show();
			if (this.WindowState == FormWindowState.Minimized)
			{
				this.WindowState = FormWindowState.Normal;
			}
			this.BringToFront();
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
#if !DEBUG
            DialogResult dr = SBPweb.Controls.Windows.Common.MessageBox.Show("Do you really want to exit the application?", "Confirm exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
            if (dr == DialogResult.Yes)
            {
                Terminate();
            }
#else
			Terminate();
#endif
		}

		#endregion

		#endregion

		#region UI Event handlers

		private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
		{
#if DEBUG
            Terminate();
#else
            // minimize the application to the system tray
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                Hide();

                niNotify.ShowBalloonTip(2000, "Workbench 2.0", "The Workbench is still running... \nClick here to show the main form.", ToolTipIcon.Info);
            }
#endif
        }

		#endregion

		#region Persistency

		private void LoadPersistency()
		{
			if (PersistenceService != null)
			{
				PersistencyDictionary state = PersistenceService.Load(this);

				string formSize = state.GetString("FormSize", this.Size.Width.ToString() + ";" + this.Size.Height.ToString());
				string[] splittedSize = formSize.Split(';');
				if (splittedSize.Length == 2)
				{
					int width = this.Width;
					int height = this.Height;
					if (int.TryParse(splittedSize[0], out width) && int.TryParse(splittedSize[1], out height))
					{
						this.Size = new System.Drawing.Size(width, height);
					}
				}

				string formLocation = state.GetString("FormLocation", this.Location.X.ToString() + ";" + this.Location.Y.ToString());
				string[] splittedLocation = formLocation.Split(';');
				if (splittedLocation.Length == 2)
				{
					int x = this.Location.X;
					int y = this.Location.Y;
					if (int.TryParse(splittedLocation[0], out x) && int.TryParse(splittedLocation[1], out y))
					{
						this.Location = new System.Drawing.Point(x, y);
					}
				}

				string windowState = state.GetString("WindowState", this.WindowState.ToString());
				try
				{
					FormWindowState fws = (FormWindowState)Enum.Parse(typeof(FormWindowState), windowState);
					this.WindowState = fws;
				}
				catch /*(Exception ex)*/ { }

                LogManager.WriteVerbose(this, "Persistency loaded for host module.", "General");
			}
		}

		private void SavePersistency()
		{
			if (PersistenceService != null && LocalizationExtender.Culture != null)
			{
				PersistencyDictionary state = PersistenceService.Load(this);
				if (this.WindowState == FormWindowState.Normal)
				{
					state.SetString("FormSize", this.Size.Width.ToString() + ";" + this.Size.Height.ToString());
					state.SetString("FormLocation", this.Location.X.ToString() + ";" + this.Location.Y.ToString());
				}
				state.SetString("WindowState", this.WindowState.ToString());

                PersistenceService.Save(this, state);
                LogManager.WriteVerbose(this, "Persistency saved for host module.", "General");
			}
		}

		public IPersistable ParentPersistable
		{
			get 
			{
				return null;
			}
		}

		#endregion

	}

    //see http://west-wind.com/weblog/posts/240.aspx for details
    internal static class MemoryManagement
    {
        private static System.Threading.Timer mTimer;
        private static int mIntervalInSeconds = 60;

        internal static bool Enabled
        {
            get
            {
                return mTimer == null ? false : true;
            }
            set
            {
                if (value)
                {
                    mTimer = new System.Threading.Timer(new System.Threading.TimerCallback(TimerCallback), new object(), mIntervalInSeconds * 1000, mIntervalInSeconds * 1000);
                }
                else
                {
                    mTimer.Dispose();
                    mTimer = null;
                }
            }
        }

        internal static int IntervalInSeconds
        {
            get
            {
                return mIntervalInSeconds;
            }
            set
            {
                mIntervalInSeconds = value;
            }
        }

        static MemoryManagement()
        {
            System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
            loProcess.PriorityClass = System.Diagnostics.ProcessPriorityClass.AboveNormal;
        }

        private static void TimerCallback(object state)
        //private static void mTimer_Tick(object sender, EventArgs e)
        {
            System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.BelowNormal;
            MinimizeWorkingSets();
        }

        internal static void MinimizeWorkingSets()
        {
            System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
            try
            {
                loProcess.MaxWorkingSet = loProcess.MaxWorkingSet;
            }
            catch (Exception e)
            {
                Program.Loader.Host.LogManager.WriteError(Program.Loader.Host, e, "General");
            }
        }
    }
}
